<template>
  <el-dialog
    v-if="customCalculationDialog"
    v-model="customCalculationDialog"
    :title="title"
    width="1048px"
    top="8.4vh"
    append-to-body
    destroy-on-close
    :close-on-click-modal="false"
    :class="`${customClass} ${visualThemeClassName} ${xvueNameSpace}`"
  >
    <div
      v-loading="isLoading"
      class="custom-calculation-main"
      :class="xvueTheme"
    >
      <div class="tipsContent">{{ tipsContent }}</div>
      <div class="panel-all">
        <div class="panel-outer">
          <div class="function-panel panel">
            <el-collapse v-model="activeNamesFunction">
              <el-collapse-item
                v-for="(item, index) in formula"
                :key="index"
                :name="index"
              >
                <template #title>
                  <span
                    class="collapse-title"
                  > {{ item.name }}({{ item.child.length }}) </span>
                </template>
                <div
                  v-for="(subItem, subIndex) in item.child"
                  :key="subIndex"
                  class="collapse-item"
                  @click="showFormulaInfo(subItem)"
                  @dblclick="formulaClick(subItem)"
                >
                  <span class="collapse-text">{{ subItem.name }}</span>
                </div>
              </el-collapse-item>
            </el-collapse>
          </div>
        </div>

        <div class="panel-outer">
          <div class="field-panel panel">
            <el-collapse v-model="activeNamesField">
              <el-collapse-item
                v-for="(item, index) in fields"
                :key="index"
                :name="index"
              >
                <template #title>
                  <span
                    class="collapse-title"
                  > {{ item.fieldName }}({{ item.fieldChild.length }}) </span>
                </template>
                <div
                  v-for="(subItem, subIndex) in item.fieldChild"
                  :key="subIndex"
                  class="collapse-item"
                  @dblclick="fieldClick(subItem)"
                >
                  <span class="collapse-text">{{ subItem.fieldCode }}</span>
                </div>
              </el-collapse-item>
            </el-collapse>
          </div>
        </div>

        <div
          id="editorArea-div"
          class="code-panel panel"
        >
          <textarea
            id="editorArea"
            ref="mycode"
            class="codesql"
            style="height:400px;width:300px;"
          ></textarea>
          <div class="formula-description-box">
            <el-collapse v-model="activeNamesFormulaDescriptionBox">
              <el-collapse-item
                v-for="(item, index) in formulaDescription"
                :key="index"
                :name="index"
              >
                <template #title>
                  <span
                    class="collapse-title"
                  >{{ item.name }}</span>
                </template>
                <div
                  v-for="(subItem, subIndex) in item.child"
                  :key="subIndex"
                  class="collapse-item"
                >
                  <span class="collapse-text">{{ subItem.description }}</span>
                </div>
              </el-collapse-item>
            </el-collapse>
          </div>
        </div>
      </div>

      <div class="action-button-group">
        <el-button
          class="button-sure"
          size="small"
          type="primary"
          :loading="saving"
          @click="selected()"
        >
          {{ $demoi18n('btn.confirm') }}
        </el-button>
        <el-button
          class="button-cancel"
          size="small"
          @click="closeDialog()"
        >
          {{ $demoi18n('btn.cancel') }}
        </el-button>
      </div>
    </div>
  </el-dialog>
</template>
<script>
import EventBus from '@/event-bus/EventBus.js';
import { checkStringType } from '@/utils/util';
import 'codemirror/addon/edit/matchbrackets';
import 'codemirror/addon/hint/show-hint.css';
import 'codemirror/addon/selection/active-line';
import CodeMirror from 'codemirror/lib/codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/theme/ambiance.css';

// 取自codemirror的show-hint
import { nextTick, shallowRef } from 'vue';
import formula from './formula';
import hintDark from './hint-dark';
import hintLight from './hint-light';
import { checkBrace } from './utils';

export default {
  name: 'CustomCalculation',
  components: {},
  props: ['title', 'code', 'calcList', 'theme', 'widgetInstanceId', 'type', 'index', 'tableName', 'fieldArr'],
  emits: [],
  data() {
    return {
      xvueNameSpace: process.env.xvueNameSpace, // 给挂载在body下的元素加上主类名
      customClass: `custom-calculation-dialog custom-calculation-dialog-${window._adoPremise.uc.theme || 'light'}`,
      xvueTheme: window._adoPremise.uc.theme, // 'dark',
      formula,

      curRow: null, // 当前行
      fields: [],
      customCalculationDialog: false,
      saving: false,
      isLoading: false,
      activeNamesFunction: [0],
      activeNamesField: [0],
      activeNamesFormulaDescriptionBox: [0],

      // 编辑器实例
      editor: null,

      fnList: [],
      fieldList: [],

      searchFormula: '',
      searchField: '',
      formulaDescription: [],
      tipsContent: this.$demoi18n('customCalculation.tipsContent'),
    };
  },
  watch: {
    customCalculationDialog(newVal) {
      if (newVal) {
        nextTick(() => {
          this.initTextarea();
        });
      }
    },
    fieldArr(newVal) {
      if (!newVal || !newVal.length) {
        return;
      }

      // 将接口数据转为字段列表
      const addItemToFields = (name, obj) => {
        const item = this.fields.find(f => String(f.fieldName) === String(name));
        if (item) {
          item.fieldChild.push({
            fieldCode: obj.option_label, // code
            type: obj.type,
          });
        } else {
          this.fields.push({
            fieldName: name,
            fieldChild: [
              {
                fieldCode: obj.option_label, // code
                type: obj.type,
              },
            ],
          });
        }
      };
      this.fields = [];
      newVal.forEach(item => {
        const type = (item.type || '').split('(')[0];
        if (checkStringType('number', type)) {
          addItemToFields(this.$demoi18n('customCalculation.numberField'), item);
        } else if (checkStringType('text', type)) {
          addItemToFields(this.$demoi18n('customCalculation.textField'), item);
        } else if (checkStringType('date', type)) {
          addItemToFields(this.$demoi18n('customCalculation.timeField'), item);
        } else {
          addItemToFields(this.$demoi18n('customCalculation.otherField'), item);
        }
      });
      this.getFieldList();
    },
  },
  created() {
    this.getFnList();

    // 动态加载hint样式
    if (this.xvueTheme === 'light') {
      this.addCssByStyle(hintLight);
    } else if (this.xvueTheme === 'dark') {
      this.addCssByStyle(hintDark);
    } else {}
  },
  methods: {
    addCssByStyle(cssString) {
      const style = document.createElement('style');

      style.setAttribute('type', 'text/css');

      if (style.styleSheet) {
        style.styleSheet.cssText = cssString;
      } else {
        const cssText = document.createTextNode(cssString);

        style.appendChild(cssText);
      }

      const heads = document.getElementsByTagName('head');

      if (heads.length) {
        heads[0].appendChild(style);
      } else {
        document.documentElement.appendChild(style);
      }
    },
    addCssByLink(url) {
      const link = document.createElement('link');
      link.setAttribute('rel', 'stylesheet');
      link.setAttribute('type', 'text/css');
      link.setAttribute('href', url);

      const heads = document.getElementsByTagName('head');
      if (heads.length) {
        heads[0].appendChild(link);
      } else {
        document.documentElement.appendChild(link);
      }
    },

    queryFormula(str, cb) {
      const fnList = [];
      formula.forEach(item => {
        item.child.forEach(subItem => {
          fnList.push(subItem);
        });
      });
      const result = str ?
        fnList.filter(f => f.name.toLowerCase().indexOf(str.toLowerCase()) === 0) :
        fnList;
      return result;
    },

    // 显示函数说明
    showFormulaInfo(item) {
      this.formulaDescription = [
        {
          name: item.code,
          child: [
            {
              description: item.description,
            },
          ],
        },
      ];
    },

    // 函数字段双击,填入编辑器中
    formulaClick(item) {
      let cur = this.editor.getCursor();
      this.editor.replaceRange(`${item.name}()`, cur, cur, '+insert');
      this.editor.focus();
      cur = this.editor.getCursor();
      cur.ch = cur.ch - 1;
      this.editor.setCursor(cur);
    },

    // 参数字段双击,填入编辑器中
    fieldClick(item) {
      const cur = this.editor.getCursor();

      this.editor.replaceRange(`[${item.fieldCode}]`, cur, cur, '+insert');
      this.editor.focus();
    },

    // 获取函数字段列表
    getFnList() {
      // 函数个数
      formula.forEach(item => {
        item.child.forEach(subItem => {
          this.fnList.push(subItem.name);
        });
      });
    },

    // 获取参数字段列表
    getFieldList() {
      this.fields.forEach(item => {
        item.fieldChild.forEach(subItem => {
          this.fieldList.push(subItem.fieldCode);
        });
      });
    },

    // 初始化编辑器
    initTextarea() {
      // 定义我们需要高亮的关键字
      const formulaList = this.fnList;
      const { fieldList } = this;
      const bracketsList = ['(', ')', '[', ']'];

      // 定义想要自动补全的words
      const hintList = [...formulaList, ...fieldList];
      const theme = 'light '; // 设置主题，不设置的会使用默认主题，后续当做风格class
      // 自定义mode
      CodeMirror.defineMode('myMode', config => ({
        token: stream => {
          if (stream.eatSpace()) {
            return null;
          }
          stream.eatWhile(/[\$\w\u4e00-\u9fa5]/);

          const cur = stream.current();
          const existFormula = formulaList.some(item => item === cur);
          const existField = fieldList.some(item => item === cur);
          const existBracket = bracketsList.some(item => item === cur);
          if (existFormula) {
            return 'formula';
          }
          if (existField) {
            return 'myfield';
          }
          if (existBracket) {
            return 'myBracket';
          }

          return stream.next();
        },
      }));

      // 自定义提示
      CodeMirror.registerHelper('hint', 'myMode', cm => {
        const cur = cm.getCursor();
        const token = cm.getTokenAt(cur);
        const { start } = token;
        const end = cur.ch;
        const str = token.string;

        const list = hintList.filter(item => item.indexOf(str) === 0);

        if (list.length) {
          return {
            list: list,
            from: CodeMirror.Pos(cur.line, start),
            to: CodeMirror.Pos(cur.line, end),
          };
        }
        return null;
      });

      this.editor = shallowRef(CodeMirror.fromTextArea(document.getElementById('editorArea'), {
        theme: theme,
        autofocus: true,
        closeOnUnfocus: false,
        matchBrackets: true, // 是否添加匹配括号高亮
        mode: 'myMode', // 自定义的mode名称
      }));

      // 设置初始值
      this.editor.getDoc().setValue(this.code);

      // cur 没调好

      // 这里实现的功能就是按下左括号，自动添加右括号
      this.editor.addKeyMap({
        name: 'autoInsertParentheses',
        '\'(\'': cm => {
          const cur = cm.getCursor();

          cm.replaceRange('()', cur, cur, '+insert');
          cm.document.setCursor({ line: cur.line, ch: cur.ch + 1 });
        },
      });

      this.editor.addKeyMap({
        name: 'autoInsertBrackets',
        '\'[\'': cm => {
          const cur = cm.getCursor();

          cm.replaceRange('[]', cur, cur, '+insert');
          cm.document.setCursor({ line: cur.line, ch: cur.ch + 1 });
        },
      });

      this.editor.on('inputRead', (editor, change) => {
        this.editor.showHint();

        // 校验公式是否合法
        const document = this.editor.getDoc();
        const { lines } = document.children[0];
        const flag = this.cheakValidation(lines);
      });
    },
    cheakValidation(lines) {
      const lineContent = 'mod)';
      let fnNum = 0;
      let fnIndex = 0;
      let fnName = '';
      let isLegal = true;

      // 函数个数
      formula.forEach(item => {
        item.child.forEach(subItem => {
          const reg = new RegExp(subItem.name, 'g');
          const result = lineContent.match(reg);
          if (result && result.length) {
            fnNum += result.length;
            fnIndex = lineContent.search(reg);
            fnName = subItem.name;
          }
        });
      });
      if (fnNum === 1) {
        isLegal = checkBrace(lineContent, fnName, fnIndex);
      } else {
        isLegal = false;
      }
      return isLegal;
    },
    openDialog(row) {
      this.customCalculationDialog = true;
      this.curRow = row;
    },
    closeDialog() {
      this.customCalculationDialog = false;
    },
    selected() {
      // 新增还是编辑
      const code = this.editor.getValue();
      const obj = {
        code,
        index: this.index,
        type: this.type,
      };
      EventBus.$emit(`save_customCalculation_${this.widgetInstanceId}`, { obj, row: this.curRow });
      this.closeDialog();
    },
  },
};
</script>

<style lang="less">
// 这个不能用scoped
.custom-calculation-dialog {
  .custom-calculation-main {
    padding: 20px 30px 78px 30px;

    .tipsContent {
      line-height: 1.5;
      padding: 15px;
      margin-bottom: 15px;
    }
    .panel-all {
      display: flex;
      position: relative;
    }

    .panel-outer {
      width: 328px;
      .search-box {
        padding: 20px;
      }
    }

    .panel {
      display: inline-block;

      :deep(.panel-search) {
        margin-bottom: 20px;
        .el-input__inner {
          border-radius: 0;
        }
        .el-input__icon {
        }
      }

      :deep(.el-collapse) {
        border-top: unset;
        border-bottom: unset;
        .el-collapse-item {
          cursor: pointer;
          .el-collapse-item__header {
            flex: 1 0 auto;
            order: -1;
            border-bottom: unset;
            height: 34px;
            line-height: 34px;
            .collapse-title {
              flex: 1 0 90%;
              order: 1;
            }
          }
          .el-collapse-item__wrap {
            margin-left: 21px;
            border-bottom: unset;
            .el-collapse-item__content {
              padding-bottom: 3px;
              padding-top: 3px;
            }
            .collapse-item {
              margin-left: 14px;
              height: 26px;
              line-height: 26px;
              .collapse-text {
              }
            }
          }
        }
      }
    }
    .function-panel {
      width: 288px;
      height: 499px; //无搜索框
      padding: 0 20px 20px 20px;
      border-right: unset;
      border-top: unset;
      overflow-y: auto;
      overflow-x: hidden;
    }
    .field-panel {
      width: 288px;
      height: 499px; //无搜索框
      padding: 0 20px 20px 20px;
      border-right: unset;
      border-top: unset;
      overflow-y: auto;
      overflow-x: hidden;
    }
    .code-panel {
      width: 328px;
      height: 507px;
      .codesql {
        font-size: 11pt;
        font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
          Bitstream Vera Sans Mono, Courier New, monospace, serif;
      }

      .formula-description-box {
        height: calc(100% - 300px);
        .el-collapse {
          height: 100%;
          overflow: hidden;
          word-break: break-word;
          .el-collapse-item.is-active {
            height: 100%;
            .el-collapse-item__wrap {
              height: calc(100% - 48px);
              overflow: auto;
            }
          }
        }
      }

      :deep(.el-collapse) {
        border-top: unset;
        border-bottom: unset;
        .el-collapse-item {
          .el-collapse-item__header {
            flex: 1 0 auto;
            order: 1;
            border-bottom: unset;

            height: 34px;
            line-height: 34px;
            .collapse-title {
              flex: 1 0 90%;
              order: -1;
              margin-left: 20px;
              font-weight: bolder;
            }
            .el-collapse-item__arrow {
              margin-left: -20px;
            }
          }
          .el-collapse-item__wrap {
            margin-left: 20px;
            margin-right: 10px;
            border-bottom: unset;
            overflow: unset;
            .el-collapse-item__content {
              padding-bottom: 3px;
              padding-top: 3px;
            }
            .collapse-item {
              margin-left: 0px;
              height: 26px;
              line-height: 26px;
              cursor: default;
              .collapse-text {
              }
            }
          }
        }
      }
    }

    .action-button-group {
      position: absolute;
      right: 30px;
      bottom: 25px;
      .button-sure {
        padding: 9px 35px;
        border-radius: 0;
      }
      .button-cancel {
        padding: 9px 35px;
        border-radius: 0;
      }
    }
  }
  .dark {
    background: #071f30;
    .tipsContent {
      background-color: #142f44;
      color: #ffffff;
    }
    .panel-outer {
      border: 1px solid #116584;
      border-right: unset;
      :deep(.panel-search) {
        .el-input__inner {
          border-color: #588ba8;
          color: #fff;
          background-color: #091a2d;
        }
        .el-input__icon {
          color: #588ba8;
        }
      }
    }

    .panel {
      background-color: #071f30;
    }
    .code-panel {
      border: 1px solid #116584;
      :deep(.CodeMirror) {
        background-color: #000c17;
        color: #ffffff;
      }

      .formula-description-box {
        border-top: 1px solid #116584;
      }
    }
    .el-collapse {
      border-top: 1px solid #116584;
      border-bottom: 1px solid #116584;
      .el-collapse-item {
        .el-collapse-item__header {
          background-color: #064559;
          border-color: #071f30;
          color: #98cae6;
        }
        .el-collapse-item__wrap {
          background-color: transparent;
          border-bottom: 1px solid #116584;
          .el-collapse-item__content {
            background-color: #142f44;
            color: #98cae6;
          }
        }
      }
    }
    .action-button-group {
      .button-sure {
        background-color: #0eb4c2;
        border-color: #0eb4c2;
        color: #fff;
      }
      .button-cancel {
        background-color: #064559;
        border-color: #064559;
        color: #fff;
      }
    }
    #editorArea-div {
      .CodeMirror {
        background-color: #071f30;
        color: #ffffff;
      }
      .cm-s-default .cm-keyword {
        color: #708;
        background: blue;
      }
      .cm-myfield {
        color: #4db8fe;
      }
      .cm-formula {
        color: #dcdc8b;
      }
      .cm-myBracket {
        color: rgb(255, 0, 221);
      }

      .CodeMirror-cursor {
        border-left: 1px solid #f8f8f0;
      }
    }
  }
  .light {
    .tipsContent {
      background-color: #f5f5f5;
    }
    border-radius: 8px;
    background: #ffffff;
    .panel-outer {
      border: 1px solid #dddddd;
      border-right: unset;
    }

    .panel {
      background-color: #fff;

      :deep(.el-collapse) {
        .el-collapse-item {
          .el-collapse-item__header {
            .collapse-title {
            }
          }
          .el-collapse-item__wrap {
            .collapse-item {
              .collapse-text {
              }
            }
          }
        }
      }
    }
    .function-panel {
      border-right: unset;
      border-top: unset;
      .el-collapse {
        .el-collapse-item {
          .el-collapse-item__wrap {
            .el-collapse-item__content {
              background-color: #f5f5f5;
            }
          }
        }
      }
    }
    .field-panel {
      border-right: unset;
      .el-collapse {
        .el-collapse-item {
          .el-collapse-item__wrap {
            .el-collapse-item__content {
              background-color: #f5f5f5;
            }
          }
        }
      }
    }
    .code-panel {
      border: 1px solid #dddddd;
      :deep(.CodeMirror) {
      }

      .formula-description-box {
        border-top: 1px solid #ddd;
      }

      :deep(.el-collapse) {
        .el-collapse-item {
          .el-collapse-item__header {
            .collapse-title {
            }
          }
          .el-collapse-item__wrap {
            .collapse-item {
              .collapse-text {
              }
            }
          }
        }
      }
    }
    .action-button-group {
      .button-sure {
      }
      .button-cancel {
      }
    }
    #editorArea-div {
      .cm-s-default .cm-keyword {
        color: #708;
        background: blue;
      }
      .cm-myfield {
        color: #0d2f9c;
      }
      .cm-formula {
        color: rgb(255, 0, 221);
      }
      .cm-myBracket {
        color: rgb(255, 0, 221);
      }

      .CodeMirror-cursor {
        border-left: 1px solid #000;
      }
    }
  }
}

// 自带蓝黑风格样式
.custom-calculation-dialog {
  .el-dialog__header {
    height: 40px;
    line-height: 40px;
    background: #122b40;
    padding: 0;
    padding-left: 20px;
    .el-dialog__title {
      font-size: 16px;
      color: #fff;
    }
    .el-dialog__headerbtn {
      position: absolute;
      top: 0px;
      right: 20px;

      padding: 0;
      background: 0 0;
      border: none;
      outline: 0;
      cursor: pointer;
    }
    .el-dialog__headerbtn .el-dialog__close {
      color: #fff;
    }
  }
  .el-dialog__body {
    padding: 0px !important;
    color: #606266;
  }
}

// 明亮风格样式
.custom-calculation-dialog-light {
  border-radius: 8px;
  .el-dialog__header {
    border-radius: 8px;
    background: #edf3fc;
    .el-dialog__title {
      color: #333;
    }
    .el-dialog__headerbtn {
      top: 12px;
    }
    .el-dialog__headerbtn .el-dialog__close {
      color: #333;
    }
  }
  .el-dialog__body {
    color: #606266;
  }
}
.el-image-viewer__close {
  color: #fff;
}
</style>
<style lang="less">
.dark {
  /* *滚动条* */
  ::-webkit-scrollbar {
    width: 4px !important;
    height: 4px !important;
  }

  ::-webkit-scrollbar-thumb {
    /* 滚动条里面小方块 */
    background: #00f0ff !important;
  }

  ::-webkit-scrollbar-track {
    /* 滚动条里面轨道 */
    background: #1a405f !important;
  }

  ::-webkit-scrollbar-corner {
    background-color: #1a405f !important;
  }

  .scroll-content::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }
}
.light {
  /* *滚动条* */
  ::-webkit-scrollbar {
    width: 4px !important;
    height: 4px !important;
  }

  ::-webkit-scrollbar-thumb {
    /* 滚动条里面小方块 */

    background: #65c7f8;
  }

  ::-webkit-scrollbar-track {
    /* 滚动条里面轨道 */
    background: #efefef;
  }
  ::-webkit-scrollbar-corner {
    background-color: #efefef;
  }

  .scroll-content::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }
}
</style>
